/*
	Copyright (c) 2009-2011, Stefan Webb.

	This file is part of SimpleML. Please read the file "license.txt", 
	which contains the conditions under which this software is distributed.
*/

/*!
	\file console.cpp
	\author Stefan Webb
	\brief Definition of Console class members.
*/

#include "stdafx.h"

/* Default constructor. */
Console::Console()
{
	// Get console handles.
	hStdOut_ = GetStdHandle(STD_OUTPUT_HANDLE);
	if (hStdOut_ == INVALID_HANDLE_VALUE)
		// TODO: More sophisticated Win32 error reporting using GetLastError
		(error << L"Could not open console output.").exception();

	hStdIn_ = GetStdHandle(STD_INPUT_HANDLE);
	if (hStdIn_ == INVALID_HANDLE_VALUE)
		// TODO: More sophisticated Win32 error reporting using GetLastError
		(error << L"Could not open console input.").exception();
}

/* Default destructor. */
Console::~Console()
{
	// Free the resource by closing handles.
	CloseHandle(hStdOut_);
	CloseHandle(hStdIn_);
}

/* Pauses thread until a key is pressed. */
void Console::pressAnyKey()
{
	// Some variables required for Win32 functions.
	TCHAR  ch;
	DWORD  mode, count;
	
	// Switch to raw mode
	GetConsoleMode(hStdIn_, &mode);
	SetConsoleMode(hStdIn_, 0);

	// Wait for the user's response
	WaitForSingleObject(hStdIn_, INFINITE);

	// Read the (single) key pressed
	ReadConsole(hStdIn_, &ch, 1, &count, NULL);

	// Restore the console to its previous state
	SetConsoleMode(hStdIn_, mode);
}

/* Set output radix for numbers. */
void Console::setRadix(RadixState radix)
{
	// TODO: Replace this with inherited template version when I learn more about templates.
	radix_ = radix;
}

/* Operator for setting radix. Makes it neater to chain operations. */
Console& Console::operator<<(RadixState radix)
{
	setRadix(radix);
	return *this;
}

/* Get current output radix for numbers. */
RadixState Console::getRadix()
{
	return radix_;
}

/* Operator for setting where console output is directed. */
Console& Console::operator<<(ConsoleState destination)
{
	setState(destination);
	return *this;
}

/* Operator for writing UTF-8 string to console. */
Console& Console::operator<<(const utf8* string)
{
	print(string);
	return *this;
}
	
/* Operator for writing UTF-16 string to console. */
Console& Console::operator<<(const utf16* string)
{
	print(string);
	return *this;
}

/* Operator for writing signed byte to console. */
Console& Console::operator<<(const char int8)
{
	print(int8);
	return *this;
}

/* Operator for writing unsigned byte to console. */
Console& Console::operator<<(const unsigned char uint8)
{
	print(uint8);
	return *this;
}

/* Operator for writing short signed integer to console. */
Console& Console::operator<<(const short int16)
{
	print(int16);
	return *this;
}

/* Operator for writing short unsigned integer to console. */
Console& Console::operator<<(const unsigned short uint16)
{
	print(uint16);
	return *this;
}

/* Operator for writing signed integer to console. */
Console& Console::operator<<(const int int32)
{
	print(int32);
	return *this;
}

/* Operator for writing unsigned integer to console. */
Console& Console::operator<<(const unsigned int uint32)
{
	print(uint32);
	return *this;
}

/* Operator for writing long integer to console. */
Console& Console::operator<<(const long long int64)
{
	print(int64);
	return *this;
}

/* Operator for writing unsigned long integer to console. */
Console& Console::operator<<(const unsigned long long uint64)
{
	print(uint64);
	return *this;
}

/* Operator for writing single precision floating number to console. */
Console& Console::operator<<(const float number)
{
	print(number);
	return *this;
}

/* Operator for writing double precision floating number to console. */
Console& Console::operator<<(const double number)
{
	print(number);
	return *this;
}

/* Operator for writing pointer address to console. */
Console& Console::operator<<(const void* pointer)
{
	print(pointer);
	return *this;
}

/* Write UTF-8 string to console. */
void Console::print(const utf8* string)
{
	// Calculate length and if any non-ANSI characters
}

/* Write UTF-16 string to console. */
void Console::print(const utf16* string)
{
	unsigned int charsWritten;
	// Printing zero pointer results in error, hence we need to check
	if (string)
		WriteConsole(hStdOut_, string, wcslen(string), (LPDWORD) &charsWritten, NULL);
	else
		*this << L"(empty string)";
}

/* Write signed byte to console. */
void Console::print(const char int8)
{
	// Go through string to calculate length, checking if non-ASCII characters

	// If no ascii characters then can use ANSI version of write console

	// Otherwise will need to convert to UTF-16
}

/* Write unsigned byte to console. */
void Console::print(const unsigned char uint8)
{

}

/* Write signed word to console. */
void Console::print(const short int16)
{

}

/* Write unsigned word to console. */
void Console::print(const unsigned short uint16)
{

}

/* Write signed integer to console. */
void Console::print(const int int32)
{

}

/* Write unsigned integer to console. */
void Console::print(const unsigned int uint32)
{

}

/* Write signed long integer to console. */
void Console::print(const long long int64)
{

}

/* Write unsigned long integer to console. */
void Console::print(const unsigned long long uint64)
{

}

/* Write single precision floating number to console. */
void Console::print(const float number)
{

}

/* Write double precision floating number to console. */
void Console::print(const double number)
{

}

/* Write pointer address to console. */
void Console::print(const void* pointer)
{

}

// Stream-like operator, to fill error message with ANSI string
// Replace with WriteConsoleA version in future
/*Console& Console::operator<<(const char* text)
{
	unsigned int length = strlen(text);
	wchar_t* tempBuffer = new wchar_t[length + 1];
	for (unsigned int i = 0; i < length; i++)
		tempBuffer[i] = text[i];

	tempBuffer[length] = 0;
	(*this) << tempBuffer;
	delete [] tempBuffer;

	return *this;
}

// Stream-like operator, to fill error message with ANSI string
Console& Console::operator<<(const unsigned char* text)
{
	return (*this << (char*) text);
}

// Stream-like operator, to fill error message with Unicode string
Console& Console::operator<<(const wchar_t* text)
{
	unsigned int charsWritten;
	// Printing zero pointer results in error, hence we need to check
	if (text)
		WriteConsole(console_, text, wcslen(text), (LPDWORD) &charsWritten, NULL);
	else
		*this << L"(empty string)";
	return *this;
}

// Stream-like operator, to fill error message with integer converted to string
Console& Console::operator<<(const int number)
{
	wchar_t buffer [33];
	_itow(number, buffer, 10);
	return (*this << buffer);
}

// Stream-like operator, to fill error message with integer converted to string
Console& Console::operator<<(const unsigned int number)
{
	wprintf(L"%u", number);
	return *this;
}


// Stream-like operator, to fill error message with double converted to string
Console& Console::operator<<(double number)
{
	wprintf(L"%g", number);
	return *this;
}

// Stream-like operator, to fill error message with pointer converted to string
Console& Console::operator<<(const void* pointer)
{
	wprintf(L"%p", pointer);
	return *this;
}*/